import cv2
import numpy as np

# Read an image
img = cv2.imread("images/image.jpg")

# Display an image
cv2.imshow("image", img)
cv2.waitKey(0) # wait for a key press

# Save an image
cv2.imwrite("images/saved_img.jpg", img)

# Change the color space
gray_img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
cv2.imshow("gray_image", gray_img)
cv2.imwrite("images/gray_img.jpg", gray_img)
cv2.waitKey(0)

# Change image scale
r, c = img.shape[: 2]
resize_img = cv2.resize(img, (2 * r, 2 * c), interpolation=cv2.INTER_CUBIC)
cv2.imshow("resize_image", resize_img)
cv2.imwrite("images/resize_img.jpg", resize_img)
cv2.waitKey(0)

# Crop the image
crop_img = img[0: 200, 150: 350]
cv2.imshow("crop_image", crop_img)
cv2.imwrite("images/crop_img.jpg", crop_img)
cv2.waitKey(0)

# Translation, the transformation matrix is [[1, 0, tx], [0, 1, ty]]
r, c = img.shape[: 2]
M = np.float32([[1, 0, 100], [0, 1, 100]]) # the amount of shift is (100, 100)
trans_img = cv2.warpAffine(img, M, (c, r))
cv2.imshow("trans_image", trans_img)
cv2.imwrite("images/trans_img.jpg", trans_img)
cv2.waitKey(0)

# Rotation, the transformation matrix is [[cos(a), -sin(a)], [sin(a), cos(a)]]
r, c = img.shape[: 2]
M = cv2.getRotationMatrix2D((c/2, r/2), 90, 1) # the angle is 90
rotation_img = cv2.warpAffine(img, M, (c, r))
cv2.imshow("rotation_image", rotation_img)
cv2.imwrite("images/rotation_img.jpg", rotation_img)
cv2.waitKey(0)

# Thresholding
threshold_img = cv2.threshold(gray_img, 120, 255, cv2.THRESH_BINARY)
cv2.imshow("threshold_image", threshold_img[1])
cv2.imwrite("images/threshold_img.jpg", threshold_img[1])
cv2.waitKey(0)

# Filter, our own filter
kernel = np.array([[1, 1, 1], [1, 1, 1], [1, 1, 1]])
filter_img = cv2.filter2D(img, -1, kernel)
cv2.imshow("filter_image", filter_img)
cv2.imwrite("images/filter_img.jpg", filter_img)
cv2.waitKey(0)

# Filter, gaussian blur
gaussian_blur_img = cv2.GaussianBlur(img, (5, 5), 0)
cv2.imshow("gaussian_blur_image", gaussian_blur_img)
cv2.imwrite("images/gaussian_blur_img.jpg", gaussian_blur_img)
cv2.waitKey(0)

# Filter, median blur
median_blur_img = cv2.medianBlur(img, 5)
cv2.imshow("median_blur_image", median_blur_img)
cv2.imwrite("images/median_blur_img.jpg", median_blur_img)
cv2.waitKey(0)

# Erosion
kernel = np.ones((5, 5), np.uint8)
erosion_img = cv2.erode(img, kernel, iterations=1)
cv2.imshow("erosion_image", erosion_img)
cv2.imwrite("images/erosion_img.jpg", erosion_img)
cv2.waitKey(0)

# Dilation
kernel = np.ones((5, 5), np.uint8)
dilation_img = cv2.dilate(img, kernel, iterations=1)
cv2.imshow("dilation_image", dilation_img)
cv2.imwrite("images/dilation_img.jpg", dilation_img)
cv2.waitKey(0)

# Sobel edge detection
# in the x direction
x_edges = cv2.Sobel(gray_img, -1, 1, 0, ksize=5)
cv2.imshow("sobel_x_edges_image", x_edges)
cv2.imwrite("images/sobel_x_edges_img.jpg", x_edges)
cv2.waitKey(0)
# in the y direction
y_edges = cv2.Sobel(gray_img, -1, 0, 1, ksize=5)
cv2.imshow("sobel_y_edges_image", y_edges)
cv2.imwrite("images/sobel_y_edges_img.jpg", y_edges)
cv2.waitKey(0)
# in the x & y direction
edges = cv2.Sobel(gray_img, -1, 1, 1, ksize=5)
cv2.imshow("sobel_edges_image", edges)
cv2.imwrite("images/sobel_edges_img.jpg", edges)
cv2.waitKey(0)

# Canny edge detector
edges = cv2.Canny(gray_img, 100, 200, 5)
cv2.imshow("canny_edges_image", edges)
cv2.imwrite("images/canny_edges_img.jpg", edges)
cv2.waitKey(0)

# Contour detection
contour_img = img
thresh_img = cv2.threshold(gray_img,127,255,0)
contours, hierarchy = cv2.findContours(thresh_img[1], cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
cv2.drawContours(contour_img, contours, -1, (255,0,0), 3)
cv2.imshow("contour_image", contour_img)
cv2.imwrite("images/contour_img.jpg", contour_img)
cv2.waitKey(0)

# Template matching
inference_img = cv2.imread("images/image.jpg")
gray_inf_img = cv2.cvtColor(inference_img, cv2.COLOR_BGR2GRAY)
template_img = cv2.imread("images/crop_img.jpg")
gray_temp_img = cv2.cvtColor(template_img, cv2.COLOR_BGR2GRAY)
w, h = gray_temp_img.shape[:: -1]
output = cv2.matchTemplate(gray_inf_img, gray_temp_img, cv2.TM_CCOEFF_NORMED) # find the match
min_val, max_val, min_loc, max_loc = cv2.minMaxLoc(output) # get the location
top = max_loc
bottom = (top[0] + w, top[1] + h)
cv2.rectangle(inference_img, top, bottom, 255, 2) # draw the area
cv2.imshow("template_matching_image", inference_img)
cv2.imwrite("images/template_matching_img.jpg", inference_img)
cv2.waitKey(0)
